Building your first Enterprise JavaBean.

Overview :

In this tutorial we will learn how to create our first Enterprise JavaBean. We will then deploy this EJB on a production class, open source, and free EJB Server; JBoss. JBoss is a really popular EJB Container and is used by quite a lot of organizations World wide. We will thus also learn how to install and run JBoss Server. The client for our EJB will be a JSP page running in a separate Tomcat Server.

This tutorial consists of following topics :

i. Installing and Running JBoss Server :

You can download JBoss from JBoss web site. Current stable version is 2.4.3. Download it from their web site. Once you have downloaded it, unzip the JBoss zip file into some directory e.g. C:\JBoss. The directory structure should be something like following :

C:\JBoss
    admin
    bin
    client
    conf
    db
    deploy
    lib
    log
    tmp

This is it as far as installation of JBoss is concerned. Now to start JBoss with default configuration go to JBoss/bin directory and run the following command at the DOS prompt :

C:\JBoss\bin>run

run.bat is a batch file which starts the JBoss Server. Once JBoss Server starts, you should see huge lines of text appearing on your command prompt screen. These lines show that JBoss Server is starting. Once JBoss startup is complete you should see a message like following on your screen :

[Default] JBoss 2.4.3 Started in 0m:11s

Well done, you just installed and ran JBoss successfully on your system for the first time. To stop JBoss, simply press Ctrl + C on the command prompt and JBoss will stop, again after displaying huge lines of text.

 

ii. Installing, Configuring and Running Tomcat Server :

First download latest stable release of Tomcat Server from Tomcat web site. Current latest stable release is 4.0.1. If you are on Windows platform then you have the luxury of downloading Tomcat in an executable ( .exe ) format. So from the different types of Tomcat files available for download, select following :

 jakarta-tomcat-4.0.1.exe

Once download is complete, double click this file to start the process of Tomcat installation. Installation is quite straight forward. During setup if you are running Windows NT/2K/XP, you'll be asked if you want to install it as a service, select 'yes' if you know what as a service is and how to start and stop it. Basically allowing the Tomcat to be installed a service means that you will be able to auto-start Tomcat when Windows starts and secondly Tomcat will run in the background and you won't have to keep one command prompt window open while it is running. Both of these features are great if you are using Tomcat on production machines. During development I will suggest that you don't install Tomcat as a service.

It will also ask you where you want it to be installed. Give it any location you want or simply allow it to be installed on the default location of C:\Program Files\Apache Tomcat 4.0.

 

Configuring and Running Tomcat :

Create a new folder under the main C:\ drive and name it "Projects". Now create a new sub-folder in the C:\Projects folder and name it "TomcatJBoss". The directory structure should look like following :

C:\Projects
    TomcatJBoss

Now open conf/Server.xml file from within the Tomcat directory where you have installed it. By default this location will be :

C:\Program Files\Apache Tomcat 4.0\conf\server.xml

Some where in the middle where you can see multiple <Context> tags, add following lines between other <Context> tags :

<!-- Tomcat JBoss Context -->
<Context path="/jboss" docBase="C:\Projects\TomcatJBoss\" debug="0"
    reloadable="true" />

Now save Server.xml file. Go to Start -> Programs -> Apache Tomcat 4.0 -> Start Tomcat, to start Tomcat Server. If everything has been setup correctly, you should see following message on your command prompt.

Starting service Tomcat-Standalone
Apache Tomcat/4.0.1

Note that creating C:\Projects\TomcatJBoss folder and setting up new /jboss context in Tomcat is NOT required as far as accessing EJBs is concerned. We are doing it only to put our JSP client in a separate folder so as not to intermingle it with your other projects.

 

 

iii. Developing your first Session EJB :

Session EJBs are responsible for maintaining logic in our J2EE applications. What we did not say in that article was that Session beans are also the simplest EJBs to develop. So that's why our first EJB will be a Session bean.

As you will see in a moment, every EJB class file has two accompanying interfaces and one XML file. The two interfaces are Remote and Home interfaces. Remote interface is what the client gets to work with, in other words Remote interface should contain the methods you want to expose to your clients. Home interface is actually EJB builder and should contain methods used to create Remote interfaces for your EJB. By default Home interface must contain at least one create() method. The actual implementation of these interfaces, our Session EJB class file remains hidden from the clients. The XML file we talked about is named as "ejb-jar.xml" and is used to configure the EJBs during deployment. So in essence our EJB, which we are going to create ( we will call it FirstEJB from now onwards ) consists of following files :

com
    stardeveloper
        ejb
            session
                First.java
                FirstHome.java
                FirstEJB.java
META-INF
    ejb-jar.xml

First.java will be the Remote interface we talked about. FirstHome.java is our Home interface and FirstEJB.java is the actual EJB class file. The ejb-jar.xml deployment descriptor file goes in the META-INF folder.

Create a new folder under the C:\Projects folder we had created earlier, and name it as "EJB". Now create new sub-folder under C:\Projects\EJB folder and name it as "FirstEJB". Create a new folder "src" for Java source files in the "FirstEJB' folder. The directory structure should look like following :

C:\Projects
    TomcatJBoss
    EJB
        FirstEJB
            src

Now create directory structure according to the package com.stardeveloper.ejb.session in the "src" folder. If you know how package structure is built, it shouldn't be a problem. Anyhow, the final directory structure should like following :

C:\Projects
    TomcatJBoss
    EJB
        FirstEJB
            src
                com
                    stardeveloper
                        ejb
                            session

 

First.java :

Now create a new First.java source file in com/stardeveloper/ejb/session folder. Copy and paste following code in it:

package com.stardeveloper.ejb.session;
 
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
 
public interface First extends EJBObject {
 
    public String getTime() throws RemoteException;
}

Hit the 'save' button to save First.java source file.

Explanation :

First line is the package statement which tells that First interface belongs in the com.stardeveloper.ejb.session package :

package com.stardeveloper.ejb.session;

Next two lines are import statements for importing required classes.

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

Then comes interface declaration line which tells that this is an interface with name "First" which extends an existing interface javax.ejb.EJBObject.

Note that every Remote interface *must* always extend EJBObject interface. It is a requirement, not an option.

public interface First extends EJBObject {

Now as I said on the last page, we have to declare methods in Remote interface which we want to be called by the client ( which the client can access and call ). For simplicity, we will only declare a single method, getTime(); which will return a String object containing current time.

public String getTime() throws RemoteException;

Notice that there are no {} parenthesis with this method as it has been declared in an interace. Remote interface method's must also throw RemoteException because EJBs are distributed components and during the call to an EJB, due to some network problem, exceptional events can arise, so all Remote interface method's must declare that they can throw RemoteException in Remote interfaces.

 

 

FirstHome.java :

Let's now create the Home interface for our FirstEJB. Home interface is used to create and get access to Remote interfaces. Create a new FirstHome.java source file in com/stardeveloper/ejb/session package. Copy and paste the following code in it :

package com.stardeveloper.ejb.session;
 
import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import java.rmi.RemoteException;
 
public interface FirstHome extends EJBHome {
 
    public First create() throws CreateException, RemoteException;
}

Hit the 'save' button to save FirstHome.java source file.

Explanation :

First few lines are package and import statements. Next we declare our FirstHome interface which extends javax.ejb.EJBHome interface.

All Home interfaces *must* extend EJBHome interface.

public interface FirstHome extends EJBHome {

 

FirstHome.java :

Then we declare a single create() method which returns an instance of First Remote interface. Notice that all methods in Home interfaces as well must also declare that they can throw RemoteException. One other exception that they *must* declare that they can throw is CreateException.

public First create() throws CreateException, RemoteException;

We are done with creating Remote and Home interfaces for our FirstEJB. These two are the only things which our client will see, the client will remain absolutely blind as far as the actual implementation class, FirstEJB is concerned.

FirstEJB.java :

FirstEJB is going to be our main EJB class. Create a new FirstEJB.java source file in com/stardeveloper/ejb/session folder. Copy and paste following text in it :

package com.stardeveloper.ejb.session;
 
import javax.ejb.SessionBean;
import javax.ejb.EJBException;
import javax.ejb.SessionContext;
import java.rmi.RemoteException;
import java.util.Date;
 
public class FirstEJB implements SessionBean {
 
    public String getTime() {
        return "Time is : " + new Date().toString();
    }
 
    public void ejbCreate() {}
    public void ejbPassivate() {}
    public void ejbActivate() {}
    public void ejbRemove() {}
    public void setSessionContext(SessionContext context) {}
}

Hit the 'save' button to save FirstEJB.java source file.

Explanation :

First few lines are package and import statements. Next we declare our FirstEJB class and make it implement javax.ejb.SessionBean interface.

All Session bean implementation classes *must* implement SessionBean interface.

public class FirstEJB implements SessionBean

Our first method is getTime() which had declared in our First Remote interface. We implement that method here in our FirstEJB class. It simply returns get date and time as you can see below :

    public String getTime() {
        return "Time is : " + new Date().toString();
    }

Then come 5 callback methods which are part of SessionBean interface and since we are implementing SessionBean interface, we have to provide empty implementations of these methods. Later in other articles when will build some really useful Session beans, we will then see some use of these callback methods there, for now we don't need them.

ejb-jar.xml :

Let's now create the EJB deployment descriptor file for our FirstEJB Session bean. Create a new ejb-jar.xml file in the FirstEJB/META-INF folder. Copy and paste following text in it :

<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems,
    Inc.//DTD Enterprise JavaBeans 2.0//EN"
    "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
 
<ejb-jar>
   <description></description>
   <enterprise-beans>
      <session>
         <display-name>FirstEJB</display-name>
         <ejb-name>First</ejb-name>
         <home>com.stardeveloper.ejb.session.FirstHome</home>
         <remote>com.stardeveloper.ejb.session.First</remote>
         <ejb-class>com.stardeveloper.ejb.session.FirstEJB</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Container</transaction-type>
      </session>
   </enterprise-beans>
 
   <assembly-descriptor>
      <container-transaction>
        <method>
            <ejb-name>First</ejb-name>
            <method-name>*</method-name>
        </method>
        <trans-attribute>Supports</trans-attribute>
      </container-transaction>
 
      <security-role>
         <description>Users</description>
         <role-name>users</role-name>
      </security-role>
   </assembly-descriptor>
</ejb-jar>

 

ejb-jar.xml :

One or more EJBs are packaged inside a JAR ( .jar ) file. There should be only one ejb-jar.xml file in an EJB JAR file. So ejb-jar.xml contains deployment description for one or more than one EJBs.

There are 3 types of EJBs so ejb-jar.xml should be able to contain deployment description for all 3 types of EJBs.

Our ejb-jar.xml file for FirstEJB contains deployment description for the only EJB we have developed; FirstEJB. Since it is a Session bean, it's deployment description is contained inside <session></session> tags.

<ejb-jar>
   <description></description>
   <enterprise-beans>
      <session></session>
   </enterprise-beans>
</ejb-jar>

Now let's discuss different deployment descriptor tags inside the <session></session> tag. First is the <ejb-name> tag. The value of this tag should be name of EJB i.e. any name you think should point to your Session EJB. In our case it's value is "First". Then come <home>, <remote> and <ejb-class> tags which contain complete path to Home, Remote and EJB implementation classes. Then comes <session-type> tag whose value is either "Stateless" or "Stateful". In our case it is "Stateless" because our Session bean is stateless. Last tag is <transaction-type>, whose value can be either "Container" or "Bean". We will learn more about transactions in another article, for now it is sufficient to say that the transactions for our FirstEJB will be managed by the container.

<ejb-jar>
   <description></description>
   <enterprise-beans>
      <session>
         <display-name>FirstEJB</display-name>
         <ejb-name>First</ejb-name>
         <home>com.stardeveloper.ejb.session.FirstHome</home>
         <remote>com.stardeveloper.ejb.session.First</remote>
         <ejb-class>com.stardeveloper.ejb.session.FirstEJB</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Container</transaction-type>
      </session>
   </enterprise-beans>
</ejb-jar>

Then there is a <container-transaction> tag which tells that all methods of FirstEJB "support" transactions. We will learn more about these tags and ejb-jar.xml as we continue to learn more about transactions and security in EJB environment in other articles. For now let's move forward.

Compiling the EJB Java source files :

Our directory and file structure till now looks something like following :

C:\Projects
    TomcatJBoss
    EJB
        FirstEJB
            src
                com
                    stardeveloper
                        ejb
                            session
                                First.java
                                FirstHome.java
                                FirstEJB.java
            META-INF
                ejb-jar.xml

You can compile all the Java source file by using a command like following on the command prompt :

C:\Projects\EJB\FirstEJB\src\com\stardeveloper\ejb\
    session>javac -verbose -classpath %CLASSPATH%;C:\JBoss\client\jboss-j2ee.jar
        -d C:\Projects\EJB\FirstEJB *.java

The point to remember is to make sure jboss-j2ee.jar ( which contains J2EE package classes ) in the CLASSPATH, or you will get errors when trying to compile these classes.

If you have installed JBoss Server in a separate directory then substitute the path to jboss-j2ee.jar with the one present on your system. The point is to put jboss-j2ee.jar in the CLASSPATH for the javac, so that all EJB source files compile successfully.

We will learn how to package these .class files and .xml file into an easy to deploy JAR file.

Packaging EJB source files into a JAR file :

Till now our directory and file structure should look something like following :

C:\Projects
    TomcatJBoss
    EJB
        FirstEJB
            com
                stardeveloper
                    ejb
                        session
                            First.class
                            FirstHome.class
                            FirstEJB.class
            META-INF
                ejb-jar.xml
            src
                com
                    stardeveloper
                        ejb
                            session
                                First.java
                                FirstHome.java
                                FirstEJB.java

Now to package the class files and XML descriptor file together, run the following command at the command prompt :

C:\Projects\EJB\FirstEJB>jar cvfM FirstEJB.jar com META-INF

Running this command should produce an EJB JAR file with the name of FirstEJB.jar in the FirstEJB folder. But there is one thing still left to be done.

Adding JBoss specific configuration file :

Till now our FirstEJB.jar file contains generic EJB files and deployment description. To run it on JBoss we will have to add one other file into the META-INF folder of this JAR file, called jboss.xml. This file contains the JNDI mapping of FirstEJB.

So create a new jboss.xml file in the FirstEJB/META-INF folder where ejb-jar.xml file is present. Copy and paste the following text in it :

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS//EN"
         "http://www.jboss.org/j2ee/dtd/jboss.dtd">
<jboss>
         <enterprise-beans>
                 <session>
                          <ejb-name>First</ejb-name>
                          <jndi-name>ejb/First</jndi-name>
                 </session>
         </enterprise-beans>
</jboss>

To add this new jboss.xml file into our existing FirstEJB.jar file, run the following command at the DOS prompt :

C:\Projects\EJB\FirstEJB>jar uvfM FirstEJB.jar META-INF

Now our FirstEJB.jar is ready to be deployed to the JBoss Server.

iv. Deploying FirstEJB.jar on JBoss Server :

Deploying EJBs on JBoss is as easy as copying the FirstEJB.jar file and pasting it into the C:\JBoss\deploy folder. If JBoss is running, you should see text messages appearing on the console that this EJB is being deployed and finally deployed and started. As simple as that.

v. Creating the client JSP page :

Create new WEB-INF folder in C:\Projects\TomcatJBoss folder. Now create a new web.xml file and copy/paste following text in it :

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.3.dtd">
 
<web-app>
</web-app>

As you can see, this web.xml is almost empty and is not doing anything useful. We still created it because Tomcat will throw an error if you try to access this /jboss context that we had created earlier without creating a /WEB-INF/web.xml file.

firstEJB.jsp JSP Client page :

Create a new JSP page in the C:\Projects\TomcatJBoss folder and save it as "firstEJB.jsp". Now copy and paste the following code in it :

<%@ page import="javax.naming.InitialContext,
                 javax.naming.Context,
                 java.util.Properties,
                 com.stardeveloper.ejb.session.First,
                 com.stardeveloper.ejb.session.FirstHome"%>
<%
    long t1 = System.currentTimeMillis();
    Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY,
            "org.jnp.interfaces.NamingContextFactory");
        props.put(Context.PROVIDER_URL, "localhost:1099");
 
    Context ctx = new InitialContext(props);
    FirstHome home = (FirstHome)ctx.lookup("ejb/First");
    First bean = home.create();
    String time = bean.getTime();
    bean.remove();
    ctx.close();
    long t2 = System.currentTimeMillis();
%>
<html>
<head>
    <style>p { font-family:Verdana;font-size:12px; }</style>
</head>
<body>
<p>Message received from bean = "<%= time %>".<br>Time taken :
    <%= (t2 - t1) %> ms.</p>
</body>
</html>

Hit the 'save' button to save the firstEJB.jsp JSP page.

Explanation :

As you can see the code to connect to an *external* JNDI/EJB Server is extremely simple. First we create a Properties object and put certain values for Context.INITIAL_CONTEXT_FACTORY and Context.PROVIDER_URL properties. The value for Context.INITIAL_CONTEXT_FACTORY is the interface provided by JBoss and the value for Context.PROVIDER_URL is the location:port number where JBoss is running. Both of these properties are required to connect to an *external* JNDI Server.

    Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY,
            "org.jnp.interfaces.NamingContextFactory");
        props.put(Context.PROVIDER_URL, "localhost:1099");

We then get hold of that external JNDI Context object by creating a new InitialContext() object, it's argument being the Properties object we had created earlier.

    Context ctx = new InitialContext(props);

Next we use that external JNDI Context handle to lookup our FirstEJB running on JBoss. Notice that the argument to Context.lookup("ejb/First") is the same value we had put in the jboss.xml file to bind our FirstEJB to this name in the JNDI context. We use that same value again to look for it. Once our lookup is successful, we cast it to our FirstHome Home interface.

    FirstHome home = (FirstHome)ctx.lookup("ejb/First");

We then use create method of our FirstHome Home interface to get an instance of the Remote interface; First. We will now use the methods of our EJB's remote interface ( First ).

    First bean = home.create();

We then call the getTime() method we had created in our EJB to get the current time from JBoss Server and save it in a temporary String object.

    String time = bean.getTime();

Once we are done with our Session EJB, we use the remove method to tell the JBoss Server that we no longer need this bean instance. Next we also close the external JNDI Context.

    bean.remove();
    ctx.close();

We then display this retrieved value from getTime() method on the user screen.

vi. Running the JSP page :

Before trying to run firstJSP.jsp page, we have to do one other thing. Copy following files from C:\JBoss\client folder and paste them in the C:\Projects\TomcatJBoss\WEB-INF\lib folder. It is a must, without it firstEJB.jsp page will not run.

connector.jar
deploy.jar
jaas.jar
jboss-client.jar
jboss-j2ee.jar
jbossmq-client.jar
jbosssx-client.jar
jndi.jar
jnp-client.jar

You will also copy the FirstEJB.jar file from C:\Projects\EJB\FirstEJB folder to the C:\Projects\TomcatJBoss\WEB-INF\lib folder. Without it the Tomcat will not be able to compile firstEJB.jsp JSP page.

Running firstEJB.jsp JSP page :

Now start JBoss Server if it is not already running. Also start Tomcat Server. If it is already running, then stop it and restart it again. Open your browser and access following page :

 http://localhost:8080/jboss/firstEJB.jsp

Please substitute port number "8080" above with the port number where your Tomcat Server is running. By default it is "8080". If you have done everything as was described in this article, then you should see a result like following :